package cn.com.yang.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * CompleteFuture学习 TODO
 * 
 * @author yangyijin
 * @since 2023年10月11日-下午4:09:10
 */
public class TestCompleteFuture {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
//		run1();
//		run2();
//		run3();
//		run4();
//		run5();
		run6();
	}

	private static void run6() {
		ExecutorService multiThread = Executors.newFixedThreadPool(10);
		List<CompletableFuture<String>> futures = new ArrayList<>();
		for(int i=0;i<10;i++) {
			CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{				
				return "path";
			},multiThread) ;
			futures.add(future);
		}
		List<String> aa = new ArrayList();
		for(CompletableFuture<String> future: futures) {
			aa.add(future.join());
		}
		for(String a : aa) {
			System.out.println(a);
		}
		multiThread.shutdown();
	}

	/**
	 * 测试5 allOf:多个任务都执行完成后才执行，只有有一个任务执行异常，则get()方法会抛出异常，如果都正常，get()是null; anyOf:
	 * 是多个任务只要有一个任务执行完成，则返回的CompletableFuture执行get方法时会抛出异常，如果都是正常执行，则get返回执行完成任务的结果。
	 * @throws ExecutionException 
	 * @throws InterruptedException 
	 */
	private static void run5() throws InterruptedException, ExecutionException {
		List<CompletableFuture<List<String>>> taskList = new ArrayList<>();
		CompletableFuture<List<String>> cf7 = CompletableFuture.supplyAsync(() -> {
			List<String> list = new ArrayList<String>();
			try {
				System.out.println(Thread.currentThread() + " cf7 do something....");
				Thread.sleep(2000);
				list.add("cf7 任务完成");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("cf7 任务完成");
			return list;
		});

		taskList.add(cf7);
		CompletableFuture<List<String>> cf8 = CompletableFuture.supplyAsync(() -> {
			List<String> list = new ArrayList<String>();
			try {
				System.out.println(Thread.currentThread() + " cf8 do something....");
				Thread.sleep(5000);
				list.add("cf8 任务完成");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("cf8 任务完成");
			return list;
		});
		
		taskList.add(cf8);

		CompletableFuture<List<String>> cf9 = CompletableFuture.supplyAsync(() -> {
			List<String> list = new ArrayList<String>();
			try {
				System.out.println(Thread.currentThread() + " cf9 do something....");
				Thread.sleep(3000);
				list.add("cf9 任务完成");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("cf9 任务完成");
			return list;
		});
		taskList.add(cf9);
		
//		 CompletableFuture<Void> cfAll = CompletableFuture.allOf(cf7, cf8, cf9);
//		 System.out.println("cfAll结果->" + cfAll.get());
		
		List<String> rest = new ArrayList<>();
		//利用list收集结果
		for(CompletableFuture<List<String>> task: taskList) {
			rest.addAll(task.join()); // 获取每个任务的结果 
		}
		System.out.println("rest.size():"+rest.size());
		for(String s:rest) {
			System.out.println(s);
		}
//		CompletableFuture<Object> cfAny = CompletableFuture.anyOf(cf7, cf8, cf9);
//		System.out.println("cfAny结果->" + cfAny.get());
	}

	/**
	 * thenCombine 会将两个任务的执行结果作为所提供函数的参数，且该方法有返回值。 thenAcceptBoth
	 * 同样将两个任务的返回结果作为入参，但是无返回结果。 runAfterBoth
	 * 没有入参，也没有返回值。注意两个任务中只要一个执行异常，则将该异常信息作为指定任务执行的结果
	 * 
	 * @throws ExecutionException
	 * @throws InterruptedException
	 */
	private static void run4() throws InterruptedException, ExecutionException {
		CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
			System.out.println(Thread.currentThread() + " cf1 do something....");
			return 1;
		});

		CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {
			System.out.println(Thread.currentThread() + " cf2 do something....");
			return 2;
		});

		CompletableFuture<Integer> cf3 = cf1.thenCombine(cf2, (a, b) -> {
			System.out.println(Thread.currentThread() + " cf3 do something....");
			return a + b;
		});

		System.out.println("cf3结果->" + cf3.get());

		// 无返回
		CompletableFuture<Integer> cf4 = CompletableFuture.supplyAsync(() -> {
			System.out.println(Thread.currentThread() + " cf4 do something....");
			return 1;
		});

		CompletableFuture<Integer> cf5 = CompletableFuture.supplyAsync(() -> {
			System.out.println(Thread.currentThread() + " cf5 do something....");
			return 2;
		});

		CompletableFuture<Void> cf6 = cf4.thenAcceptBoth(cf5, (a, b) -> {
			System.out.println(Thread.currentThread() + " cf6 do something....");
			System.out.println("处理结果不返回：" + (a + b));
		});

		System.out.println("cf3结果->" + cf6.get());
	}

	/**
	 * 测试3，异步执行 阻塞获取结果后，进行计算，不改变最终结果
	 * 
	 * @throws ExecutionException
	 * @throws InterruptedException
	 */
	private static void run3() throws InterruptedException, ExecutionException {
		CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
			System.out.println("执行有返回值的异步任务");
			try {
				TimeUnit.SECONDS.sleep(5);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "Hello World";
		});
		String result = future.get();
		System.out.println(result);
		// 接着
		String result2 = future.whenComplete(new BiConsumer<String, Throwable>() {
			@Override
			public void accept(String t, Throwable u) {
				t = t + "1";
				System.out.println("任务执行后结果处理");
			}
		}).exceptionally(new Function<Throwable, String>() {
			@Override
			public String apply(Throwable t) {
				System.out.println("任务执行额外结果-异常了");
				return "发生了异常";
			}
		}).get();
		System.out.println("最终执行结果：" + result2);
	}

	/**
	 * 测试2，异步执行 阻塞获取结果
	 * 
	 * @throws ExecutionException
	 * @throws InterruptedException
	 */
	public static void run2() throws InterruptedException, ExecutionException {
		CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
			System.out.println("执行有返回值的异步任务");
			try {
				TimeUnit.SECONDS.sleep(5);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "Hello World";
		});
		String result = future.get();
		System.out.println(result);
	}

	/**
	 * 测试1
	 */
	public static void run1() {
		// 1.异步执行
		Runnable runnable = () -> {
			System.out.println("执行无返回结果任务-start");
			try {
				TimeUnit.SECONDS.sleep(5);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		};
		System.out.println("执行无返回结果任务-end");

		CompletableFuture.runAsync(runnable);
	}
}
